# -*- coding: utf-8 -*- 
"""
@Author : Chan ZiWen
@Date : 2022/6/20 21:30
File Description:

"""
import time

import numpy as np
import pandas as pd

from utils import steady
from tsmoothie import ConvolutionSmoother


__all__ = ['analysis_utils']


def is_number(s):
    """str is number"""
    try:
        if s.lower() == "nan":
            return None
        return float(s)
    except ValueError:
        return None


def sleep(log_time, distance):
    """
    注意关屏状态才有蓝牙数据；
        关屏状态下已睡觉： 一直是平稳数据，则无睡眠时间
        关屏状态下马上睡觉： 睡眠时间
        关屏状态下过段时间睡觉： 睡眠时间
    :param log_time:
    :param distance:
    :return:
    """
    res = {}
    flag = False
    for t, d in zip(log_time, distance):
        t = int(t)
        dis = is_number(d)
        if dis is not None:
            res[t] = dis if dis < 40 else 40
        else:
            if flag:  # 第一个key-value必须是有效值
                res[t] = None
                # 减少离群值影响，2，删除，找干扰因素，根据现实情况
                # print("%s key no value，is %s " % (key, res[key]))

    ############ parameter
    window_sizes = 40

    keys = list(res.keys())
    ## 生成数据
    df = pd.DataFrame(
        {'BluetoothDistance': list(res.values())},
        index=keys
    )

    # a, interpolation
    df = df.interpolate(method='linear', limit_direction='forward')

    # a, smoothing
    steady_df = list(df["BluetoothDistance"])  # steady(list(df["蓝牙距离"]))
    smoother = ConvolutionSmoother(window_len=30, window_type='ones')
    smoother.smooth([steady_df])
    smooth_data = smoother.smooth_data[0]
    smooth_data = pd.Series(smooth_data)

    # b, difference
    diff = smooth_data.diff(periods=1).rolling(window=window_sizes)

    # c, window's variance
    # sum
    rwsum = diff.sum(ddof=1)
    thres = rwsum.max() / 20.
    # var
    rwvar = diff.std(ddof=1)

    flag = 0
    n = len(rwsum)
    # assert n > 150, Warning(f"Data that it's length is '{n}' is too small ")
    if n <= 150:
        return None
    """ 循环过滤 """
    a, b = 2, 1.3
    iteration = 0
    while not flag and iteration < 2:
        # 判别后方是否有大于当前的波动
        for i, (s, v) in enumerate(zip(rwsum, rwvar)):
            if i >= n - window_sizes:
                break
            if i >= window_sizes:
                post_sum, post_var = rwsum[i + window_sizes], rwvar[i + window_sizes]
                # var 大的时候， sum可能趋向0，通过abs解决；
                # 判断条件： sum和var 两部分 存在差值时，中间有一大段边缘， 通过记录前一时间的pre值判断是否变化
                if abs(v) > abs(post_var) * b:  # 方差大
                    if (abs(s) > abs(post_sum) * a) or (abs(s) < thres):  # 保证 波动值 大，或者 趋于了零
                        flag = i
                        break
            else:
                pass
        a -= 0.1
        iteration += 1

    if flag is None:
        analysisRes = None
    else:
        analysisRes = log_time[flag]  # .replace(":", "：")
    return analysisRes


def wake(log_time, distance):
    res = {}
    flag = False
    for t, d in zip(log_time, distance):
        t = int(t)
        dis = is_number(d)
        if dis is not None:
            res[t] = dis if dis < 40 else 40
        else:
            if flag:  # 第一个key-value必须是有效值
                res[t] = None
            # 减少离群值影响，2，删除，找干扰因素，根据现实情况
            # print("%s key no value，is %s " % (key, res[key]))

    ############ parameter
    window_sizes = 30

    keys = list(res.keys())
    ## 生成数据
    df = pd.DataFrame(
        {'BluetoothDistance': list(res.values())},
        index=keys
    )

    # a, interpolation
    df = df.interpolate(method='linear', limit_direction='forward')

    # a, smoothing
    steady_df = steady(list(df["BluetoothDistance"]))
    smoother = ConvolutionSmoother(window_len=30, window_type='ones')
    smoother.smooth([steady_df])
    smooth_data = smoother.smooth_data[0]
    smooth_data = pd.Series(smooth_data)

    # b, difference
    diff = smooth_data.diff(periods=1).rolling(window=window_sizes)

    # c, window's variance
    # sum
    rwsum = diff.sum(ddof=1)
    min_sum = rwsum.min() / 3
    # var
    rwvar = diff.std(ddof=1)

    flag = None
    n = len(rwsum)
    # assert n > 150, Warning(f"Data that it's length is '{n}' is too small ")
    if n <= 150:
        return None
    """ 循环过滤 """
    a, b = 2, 1.3
    iteration = 0
    while not flag and iteration < 2:
        best_sum, best_var = 0, 0
        for i, (s, v) in enumerate(zip(rwsum, rwvar)):
            if i >= n - window_sizes:
                break
            if i >= window_sizes:
                post_sum, post_var = rwsum[i + window_sizes // 2], rwvar[i + window_sizes // 2]
                # var 大的时候， sum可能趋向0，通过abs解决；
                # 判断条件： sum和var 两部分 存在差值时，中间有一大段边缘， 通过记录前一时间的pre值判断是否变化
                # if s < post_sum/a and abs(v) < abs(post_var)/b:
                if abs(v) < abs(post_var) / b:  # 方差大
                    if abs(s) < abs(post_sum) / a:  # 保证 波动值 大，或者 趋于了零
                        if best_sum < (abs(post_sum) - abs(s)) and best_var < (abs(post_var) - abs(v)):
                            # 排除离家情况 : 取 最大负值sum的一半进行比较即可
                            if post_sum > min_sum:
                                best_var = (abs(post_var) - abs(v))
                                best_sum = (abs(post_sum) - abs(s))
                                flag = i
            else:
                pass
        a -= 0.1
        iteration += 1
    if flag is None:
        analysisRes = None
    else:
        analysisRes = log_time[flag]  # .replace(":", "：")
    return analysisRes


